package component {
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.Loader;
	import flash.display.MovieClip;
	import flash.display.Shape;
	import flash.events.Event;
	import flash.events.FocusEvent;
	import flash.events.TimerEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.system.LoaderContext;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	import flash.utils.Timer;
	
	import mx.containers.Canvas;
	import mx.controls.Image;
	import mx.core.UIComponent;
	
	
	public class AdvancedImage extends Image
	{
		
		private var _loader:Loader = new Loader();
	
		private  var _mimeType:String;
		private  var _originalWidth:Number;
		private  var _originalHeight:Number;
		private  var _aspectRatio:Number;
		private  var _containerWidth:Number=0;
		private  var _containerHeight:Number=0;
		private var _allPropertyIsSet:Boolean=false;
		private var _resetImageSize:Boolean=false;
	    private var _modeAlignement:int=1;
		private var _horizontalScrollPos:int=0;
		private var _verticaScrollPos:int=0;
		private var _stabylos:Dictionary;
		private var  _multiPageAlertVisible:Boolean=false;
		public var effectifZoom:Number=-1;
		public var viewer:AdvancedImageViewer;
		private var xZoom:Number,yZoom:Number,widthZoom:Number,heightZoom:Number;
		public var zoomMode:Boolean=false;
		
		
		
		
		//******************************************************************************************
		//    Utilities functions 
		// 
		//*******************************************************************************************
		// Obtient les données d'une image découpée en hMax x wMax pour le quadrant quad 
        
        public function get stabylos():Dictionary
        {
          return _stabylos;	
        }
        
           public function set stabylos(value:Dictionary):void
        {
           _stabylos=value;;	
        }
        
        public function get modeAlignement():int
        {
        	return _modeAlignement
        }
        
        public function set  modeAlignement(value:int):void
        {
        	_modeAlignement = value;
        }
        
		public function get resetImageSize():Boolean
		{
			return _resetImageSize;
		}

		public function set resetImageSize(value:Boolean):void
		{
			_resetImageSize = value;
		}

		private function getQuadrantDecoupeData(hMax:Number,wMax:Number,quad:Number):BitmapData{
			if(hMax < 1 || wMax < 1 || quad < 1){
				return(null);
			}
			var h:Number=Math.round(_originalHeight / hMax);
			var w:Number=Math.round(_originalWidth / wMax);
			var x:Number=wMax > 1 ?w*Math.floor((quad-1) / wMax):0;
			var y:Number=h * ((quad-1) % hMax);
			var imageData:BitmapData=new BitmapData(w,h);
			var rectangle:Rectangle = new Rectangle(x,y,w,h);
			this._originalImageData = Bitmap(_originalImage).bitmapData;
			imageData.copyPixels(this._originalImageData,rectangle,new Point(0,0));
			return(imageData);
		}

		// Obtient les données d'une image découpée en x,y,w,h exprimé en pourcentage 
		private function getPercentDecoupeData(xp:Number,yp:Number,hp:Number,wp:Number):BitmapData{
			if(_originalImage != null && Bitmap(_originalImage).bitmapData != null){
			var x:Number = Math.round((xp/100) * this._originalWidth);
			var w:Number = Math.round((wp / 100) *this._originalWidth );
			var y:Number = Math.round((yp / 100) * this._originalHeight);
			var h:Number = Math.round((hp / 100) * this._originalHeight);
			if(x > 0 && y > 0 && h > 0 && w > 0){	
				var imageData:BitmapData=new BitmapData(w,h);
				var rectangle:Rectangle = new Rectangle(x,y,w,h);
				var tempBitmap:BitmapData = new BitmapData(_originalWidth,_originalHeight);
				imageData.copyPixels(Bitmap(_originalImage).bitmapData,rectangle,new Point(0,0));
				return(imageData);				
			}
			}
			return(null);
			
		}
		
		
		 // Rotation 
	  private function rotateTransformation(img:Bitmap):Bitmap
	  {
			var angle:Number=90;
			var imgMatrix:Matrix = img.transform.matrix; 
			var centerX:Number =this.width / 2; 
			var centerY:Number = this.height / 2; 
			var centerPoint:Point = new Point(centerX, centerY); 
			var transformPoint:Point= imgMatrix.transformPoint(centerPoint); 
			//imgMatrix.translate(-transformPoint.x, -transformPoint.y);
			imgMatrix.rotate(angle * Math.PI / 180);
			//imgMatrix.translate(transformPoint.x, transformPoint.y);
			img.transform.matrix = imgMatrix;
			return img; 
		}
		
		private function rotateCurrentObject(img:UIComponent, angle:Number):DisplayObject
        {
			var imgMatrix:Matrix = img.transform.matrix; 
			var centerX:Number = img.width / 2; 
			var centerY:Number = img.height / 2; 
			var centerPoint:Point = new Point(centerX, centerY); 
			var transformPoint:Point= imgMatrix.transformPoint(centerPoint); 
                        
			//Lgoic is very simple and straight forwad, we know the Registration point of any Display Object are (0,0)i.e. 
			//the top left corner.Thats why it rotates normally around this point. 
			//imgMatrix.translate(-transformPoint.x, -transformPoint.y);
			imgMatrix.rotate(angle * Math.PI / 180);
			//imgMatrix.translate(transformPoint.x, transformPoint.y);
			img.transform.matrix = imgMatrix;
			return img; 
		  }
		

		private function createAlertLogo():Shape{
				var alh:uint=10;
		 		var alw:uint=15;
		 		var sx:uint=4;
		 		var sy:uint=6
				var alertLogo:Shape=new Shape();
				alertLogo.graphics.beginFill(0xff0000,1);
				alertLogo.graphics.moveTo(sx,sy);
				alertLogo.graphics.lineTo(sx+alw,sy+alh/2);
				alertLogo.graphics.lineTo(sx,sy+alh);
				alertLogo.graphics.lineTo(sy,sy);
				alertLogo.graphics.endFill();
				return(alertLogo);	
		}
		
		
		//******************************************************************************************************************		
		// Chargement de l'image 
		//*******************************************************************************************************************
		private var _originalImageData:BitmapData;
		private var _originalImage:Object;
		private var _imageLoaded:Boolean=false;
		//private var _workingCopy:Object;
		public var _bytes:ByteArray;
		// Indique si l'image est multipage 
	    public function get multipage():Boolean{
	    	if(this._originalImage==null){
	    		return(false);
	    	}
	    	if(this._originalImage is MovieClip){
	    		var mv:MovieClip = this._originalImage as MovieClip;
	    		return(mv.totalFrames > 1);
	    	}
	    	return(false);
	    }
		
		
		
		
		public function get containerWidth():Number
		{
			return _containerWidth;
		}

		public function set containerWidth(value:Number):void
		{
			if(value !=_containerWidth){
				_containerWidth=value;
				this.width=_containerWidth;
				this.invalidateProperties();
			} 
		}
        
        
        public function get originalHeight():Number
        {
        	return _originalHeight;
        }
        
        public function set originalHeight(value:Number):void
        {
        	 _originalHeight=value;
        }
        
        public function get originalWidth():Number
        {
        	return _originalWidth;
        }
        
        public function set originalWidth(value:Number):void
        {
        	 _originalWidth=value;
        }
        
		public function get containerHeight():Number
		{
			return _containerHeight;
		}

		public function set containerHeight(value:Number):void
		{
			if(value !=_containerHeight){
				_containerHeight=value;
				this.height=_containerHeight;
		
				this.invalidateProperties();
			} 
		}
		
		
		public function set allPropertyIsSet(value:Boolean):void{
			_allPropertyIsSet=value;
			if(_allPropertyIsSet){
				invalidateProperties();
			}
		}
		
		public function setBytes(bytes:ByteArray):void
		{
			this._bytes=bytes;
			
			if(_bytes != null && _bytes.length !=0)
			{
				callLater(loadBytes,[_bytes]);
				
			}
			else
			{
				if(source != null && source is BitmapData)
				{
					BitmapData(source).dispose();
				}
				if(_originalImage != null &&  _originalImage is BitmapData)
				{
					BitmapData(source).dispose();
				}
				
				if(_originalImageData != null &&  _originalImageData is BitmapData)
				{
					BitmapData(_originalImageData).dispose();
				}
				this.source=null;
				_originalImageData = null;
				_originalImage = null;
				this._imageLoaded=false;
			}
		}
		
		public function loadBytes(bytes:ByteArray, context:LoaderContext = null):void
		{			
			if(bytes.length>0){
				viewer.resetRotation()				
				_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onBytesLoaded);
				_loader.loadBytes(bytes, context);
			}
		}
									
		// Sauve les données de la page courrante 
		/* public function saveCurrentPageData():void{
			try{
			if(source is MovieClip){
				var movieClip:MovieClip = MovieClip(source);
				
				// width and/or height are invalid (less than or equal to zero, greater than 2880) 
				var effectifwidth:int =(_originalWidth> 2880)?2880 : _originalWidth;
				var effectifHeight:int=(_originalHeight> 2880)?2880 : _originalHeight;
				var tempBitmap:BitmapData = new BitmapData(effectifwidth,effectifHeight);
				tempBitmap.draw(Sprite(movieClip));
				_originalImageData =tempBitmap
				
			} else if(source != null)
			 {
				 _originalImageData=ObjectUtil.copy(Bitmap(source).bitmapData) as BitmapData;
			}
			}catch(e:Error)
			{
				
			}
		} */
		
			
		private function onBytesLoaded( e:Event ):void
		{
 			_originalImage=_loader.content;
			_originalWidth=_loader.contentLoaderInfo.width;
			_originalHeight=_loader.contentLoaderInfo.height;		
			_mimeType=_loader.contentLoaderInfo.contentType;
			_aspectRatio=_originalWidth / _originalHeight;			
			this.source=this._originalImage;
			viewer.updateModeAlignement();
		 	invalidateProperties();
		 	viewer.initPage();
		 	callLater(resendFocusEvent);
		 
		}
		//try recatch zoom event from a focusable component
		public function resendFocusEvent():void
		{
			if(focusManager != null && focusManager.getFocus() != null){
				 focusManager.getFocus().setFocus();
				
				 if( focusManager.getFocus() is UIComponent){
				 	 var event:FocusEvent = new FocusEvent(FocusEvent.FOCUS_IN);
				    UIComponent(focusManager.getFocus()).dispatchEvent(event);	
				    
				 }
			}
		}
		//******************************************************************************************************************		
		// Fit de l'image sur la page 
		//*******************************************************************************************************************
		
		
		// Fit de l'image sur la largeur
		public function fitPageWidth():void{
			//loadBytes(_bytes,null);
			this.source = _originalImage;
			this.width=(this.parent as Canvas).width;
			this.height=this.width* (1 / this._aspectRatio); 
			modeAlignement = 1;
			effectifZoom=-1;
			_horizontalScrollPos = 0;
			_verticaScrollPos =0;
			this.invalidateSize();
			this.invalidateDisplayList(); 
			
		}
		// Fit de l'image sur la hauteur 
		public function fitPageHeight():void{
			//loadBytes(_bytes,null);
			this.source = _originalImage;
			this.height=(this.parent as Canvas).height;
			this.width=this.height * this._aspectRatio;
			 modeAlignement = 2;
            effectifZoom=-1;
            _horizontalScrollPos = 0;
            _verticaScrollPos =0;
			this.invalidateSize();
			this.invalidateDisplayList();
		}
		
		// Fit de l'image sur la hauteur et largeur
		public function fitPageBoth():void{
			//loadBytes(_bytes,null);
			this.source = _originalImage;	
			this.width=(this.parent as Canvas).width;
			this.height=(this.parent as Canvas).height;
			 modeAlignement = 3;
            effectifZoom=-1;
            _horizontalScrollPos =0;
            _verticaScrollPos =0;
			this.invalidateSize();
			this.invalidateDisplayList();
			
		}
		
		
		//******************************************************************************************************************		
		// Zoom de l'image
		//*******************************************************************************************************************
		
		// Zoom image Zoom factor de 10 à 500 100 = image normale 
		public function zoom(zoomFactor:Number):void{
			
			this.width  =	_originalWidth;
			this.height =	_originalHeight;
			this.width 	= _originalWidth *(zoomFactor / 100);
			this.height	=	_originalHeight *(zoomFactor / 100);
 			this.invalidateSize();
			this.invalidateDisplayList();
		
		}
		
		// Reset de la taille de l'image à 100%
		public function zoomReset():void{
			//this.source= _originalImage
			this.width=_originalWidth
			this.height=_originalHeight;
            _horizontalScrollPos=0;
            _verticaScrollPos =0;
			this.invalidateSize();
			this.invalidateDisplayList();
		}
					
		//****************************************************************
		// Decoupe de l'image 
		//****************************************************************
		// Remet l'image entière après découpage
		public function resetFullImage():void{				
			//this.source =ObjectUtil.copy( _originalImage);
			this.source = _originalImage;
			this.invalidateProperties();
			this.invalidateDisplayList();		
		}
		

		
		
				
		// decoupe de l'image en hMax(hauteur) x wMax(largeur) pour le quadrant quad 
		public function decoupeImage(hMax:Number,wMax:Number,quad:Number):void{
			if(hMax < 1 || wMax < 1 || quad < 1){
				return;
			}
			var h:Number=Math.round(_originalHeight / hMax);
			var w:Number=Math.round(_originalWidth / wMax);
			var x:Number=wMax > 1 ?w*Math.floor((quad-1) / wMax):0;
			var y:Number=h * ((quad-1) % hMax);
			zoomOnPageByRectangle(x,y,h,w,true);
			Canvas(parent).horizontalScrollPolicy="off";
			Canvas(parent).verticalScrollPolicy="off";
			this.invalidateProperties();							
		} 
		
		public function zoomOnPageByRatio(ratio:int):void
		{
			this.zoom(ratio);
		}
		

		public function simpleZoom(xp:Number,yp:Number,hp:Number,wp:Number):void
		{			
			xZoom = xp;
			yZoom = yp;
			widthZoom = wp;
			heightZoom =hp;
			this.width=_originalWidth;
			this.height=_originalHeight;
			effectifZoom =0;
			zoomMode =true;
			this.invalidateSize();
			this.invalidateDisplayList();			
		}
		
		public function zoomOnPageByRectangle(xp:Number,yp:Number,hp:Number,wp:Number,ratioLock:Boolean):void{	
 		        
			  	Canvas(parent).callLater(simpleZoom,[xp,yp,hp,wp]);
			  	this.invalidateProperties();
			  	this.invalidateSize();
			   this.invalidateDisplayList();			   
		}
		
		// decoupe de l'image selon les pourcentage xp,yp,hp et wp 
		public function decoupeSquareImage(xp:Number,yp:Number,hp:Number,wp:Number):void{			
			
			var squaredData:BitmapData=getPercentDecoupeData(xp,yp,hp,wp);
			if(squaredData==null){
				return;
			}
			this.source=new Bitmap(squaredData,"auto",true);
			this.invalidateProperties();
		}
		
		
				
		//****************************************************************
		// Multipâge 
		//****************************************************************
		
	

		private var _alertTimer:Timer;
		private var _alertLogo:Shape; 
		
		
		 private function  upadteTimerAlert(evt:TimerEvent):void {
		 	if(_alertLogo==null){
		 		_alertLogo=createAlertLogo();
			}
			if(this.contains(_alertLogo)){
				this.removeChild(_alertLogo);
			} else {
				this.addChild(_alertLogo);
			}
		 }
	
			
		public function displayAlertMultipage():void{
			if(_multiPageAlertVisible){
				_alertTimer= new Timer(500);
				_alertTimer.addEventListener(TimerEvent.TIMER,upadteTimerAlert);
				_alertTimer.start();	
			}
		}
		
		public function resetAlertMultipage():void{
			if(!_multiPageAlertVisible){
				return;
			}
			if(this._alertTimer !=null){
				this._alertTimer.stop();
			}
			if(this._alertLogo !=null && this.contains(_alertLogo)){
				this.removeChild(_alertLogo);
			}
		}
		
		// donne le nombre de page 
		public function get numPages():int{
			if(this.source==null){
				return(0);
			}
			if(this.source is MovieClip){
				var mv:MovieClip = this.source as MovieClip;
				return(mv.totalFrames);
			}
			return(1);
			
		}
		
		// donne la page courrante
		public function get currentPageNum():int{
			if(this.source==null){
				return(0);
			}
			if(this.source is MovieClip){
				var mv:MovieClip = this.source as MovieClip;
				return(mv.currentFrame);
			}
			return(1);	
		}
		
		// passe à la page suivante 
		public function nextPage():void{
			if(this.source==null){
				return;
			}
			if(this.source is MovieClip){
				var mv:MovieClip = this.source as MovieClip;
				if(mv.currentFrame < mv.totalFrames){
					resetAlertMultipage();
					mv.nextFrame();
					//saveCurrentPageData();
				}
			}
		}		
		
		
		// passe à la page précédente 
		public function previousPage():void{
				if(this.source==null){
				return;
			}		
			if(this.source is MovieClip){
				var mv:MovieClip = this.source as MovieClip;
				if(mv.currentFrame > 1){
					resetAlertMultipage();
					mv.prevFrame();
					//saveCurrentPageData();
				}
			}
		}	
		// passe à la première page 
		public function firstPage():void{
				if(this.source==null){
				return;
			}		
			if(this.source is MovieClip){
				var mv:MovieClip = this.source as MovieClip;
				mv.gotoAndStop(1);
				//saveCurrentPageData();
			}
		}
		// passe à la dernière page 
		public function lastPage():void{
				if(this.source==null){
				return;
			}
			if(this.source is MovieClip){
				var mv:MovieClip = this.source as MovieClip;
				resetAlertMultipage();
				mv.gotoAndStop(mv.totalFrames);
				//saveCurrentPageData();
			}
		}
		
		// passe à la page x
		public function gotoPage(num:int):void{
				if(this.source==null){
				return;
			}		
			if(this.source is MovieClip){
				var mv:MovieClip = this.source as MovieClip;
				if(num <= mv.totalFrames){
					resetAlertMultipage();
					mv.gotoAndStop(num);
					//saveCurrentPageData();
				}
			}
		}
		//******************************************************************************************
		public function applyNegativeTransformation():void{
			//var cmf:ColorMatrixFilter= new ColorMatrixFilter(-1, 0, 0, 0, 255, 0, -1, 0, 0, 255, 0, 0, -1, 0, 255, 0, 0, 0, 1, 0);
		}
		
		//******************************************************************************************
		//    Component life cycle
		//*******************************************************************************************
		override protected function createChildren():void
		{
			super.createChildren();
			_loader.visible = false;
			addChild(_loader);
		}
		
		
		
	 	override protected function commitProperties():void{
			        super.commitProperties();
				/* 	if(this.multipage){
						this._multiPageAlertVisible=true;
						this.displayAlertMultipage();
					} */				
				} 
			
			public function updateZoomStatus():void
			{
                   if(effectifZoom != -1 && widthZoom != 0 && heightZoom !=0){
		         	    var percentWidthZoom:Number =  Canvas(parent).width/widthZoom;
						var percentHeightZoom:Number= Canvas(parent).height/heightZoom;
						effectifZoom=Math.min(percentWidthZoom,percentHeightZoom);
		         		this.width=this.width*effectifZoom;
						this.height=this.height*effectifZoom;
						_horizontalScrollPos=xZoom*effectifZoom;
						_verticaScrollPos=yZoom*effectifZoom; 		
						effectifZoom=-1;
						var ratio:int= Math.min(this.width*100/this._originalWidth,this.height*100/this._originalHeight);
						viewer.zoomFactorSlider.value = ratio;
						viewer.zoomFactorLabel.text = ratio+"%";
					
                  	}
			}
	
	override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
			super.updateDisplayList(unscaledWidth, unscaledHeight); 
					   
				
			
			
                  if(zoomMode){
                  	if(parent != null)
                  	Canvas(parent).callLater(updateZoomStatus);
				}
				else
				{
					 	if(width !=0 && originalWidth != 0){
		       	               viewer.modeAlignement =viewer. _originalModeAlignement;	  
		       	}  
				}
				 
		           
		}
				
		public function AdvancedImage()
		{
			super();
		}
	}
}